package cn.oyzh.common.log;


import cn.oyzh.common.util.JarUtil;

import java.io.File;
import java.time.Instant;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * jul日志
 *
 * @author oyzh
 * @since 2024-09-27
 */
//@UtilityClass
public class JulLog {

    /**
     * 日志对象
     */
    private static final Logger LOGGER = Logger.getLogger("JulLog");

    static {
        try {
            System.setProperty("jansi.passthrough", "true");
            LOGGER.setUseParentHandlers(false);
            JulLog.setLevel(JulLevel.DEBUG);
            // 控制台日志
            if (!JarUtil.isInJar()) {
                LOGGER.addHandler(new JulConsoleHandler());
            }
            // 文件日志
            File logFile = JulUtil.getLogFile();
            LOGGER.addHandler(new JulFileHandler(logFile));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void setLevel(JulLevel level) {
        if (level != null) {
            LOGGER.setLevel(level.toLevel());
        }
    }

    public static void trace(String format, Object... args) {
        if (LOGGER.isLoggable(Level.FINEST)) {
            LOGGER.log(record(Level.FINEST, format, args));
        }
    }

    public static void trace(String format, Throwable throwable) {
        if (LOGGER.isLoggable(Level.FINEST)) {
            LOGGER.log(record(Level.FINEST, format, throwable));
        }
    }

    public static void debug(String format, Object... args) {
        if (LOGGER.isLoggable(Level.CONFIG)) {
            LOGGER.log(record(Level.CONFIG, format, args));
        }
    }

    public static void debug(String format, Throwable throwable) {
        if (LOGGER.isLoggable(Level.CONFIG)) {
            LOGGER.log(record(Level.CONFIG, format, throwable));
        }
    }

    public static void info(String format, Object... args) {
        if (LOGGER.isLoggable(Level.INFO)) {
            LOGGER.log(record(Level.INFO, format, args));
        }
    }

    public static void info(String format, Throwable throwable) {
        if (LOGGER.isLoggable(Level.INFO)) {
            LOGGER.log(record(Level.INFO, format, throwable));
        }
    }

    public static void warn(String format, Object... args) {
        if (LOGGER.isLoggable(Level.WARNING)) {
            LOGGER.log(record(Level.WARNING, format, args));
        }
    }

    public static void warn(String format, Throwable throwable) {
        if (LOGGER.isLoggable(Level.WARNING)) {
            LOGGER.log(record(Level.WARNING, format, throwable));
        }
    }

    public static void error(String format, Object... args) {
        if (LOGGER.isLoggable(Level.SEVERE)) {
            LOGGER.log(record(Level.SEVERE, format, args));
        }
    }

    public static void error(String format, Throwable throwable) {
        if (LOGGER.isLoggable(Level.SEVERE)) {
            LOGGER.log(record(Level.SEVERE, format, throwable));
        }
    }

    private static JulLogRecord record(Level level, String format, Object... args) {
        return record(level, format, null, args);
    }

    private static JulLogRecord record(Level level, String format, Throwable throwable, Object... args) {
        // 获取线程和堆栈信息
        Thread thread = Thread.currentThread();
        StackTraceElement[] trace = thread.getStackTrace();
        StackTraceElement element = trace[Math.min(4, trace.length - 1)];
        // 日志对象
        JulLogRecord logRecord = new JulLogRecord(level, format);
        // 参数
        logRecord.setParameters(args);
        // 异常
        logRecord.setThrown(throwable);
        // 时间
        logRecord.setInstant(Instant.now());
        // 线程名称
        logRecord.setThreadName(thread.getName());
        // 线程id
        if (JulConst.isEnableThreadId()) {
            logRecord.setLongThreadID(thread.threadId());
        }
        // 行号
        logRecord.setLineNumber(element.getLineNumber());
        // class名称
        logRecord.setSourceClassName(element.getClassName());
        // 方法名
        logRecord.setSourceMethodName(element.getMethodName());
        return logRecord;
    }

    public static boolean isTraceEnabled() {
        JulLevel level = JulLevel.ofLevel(LOGGER.getLevel());
        return level.ordinal() >= JulLevel.TRACE.ordinal();
    }

    public static boolean isDebugEnabled() {
        JulLevel level = JulLevel.ofLevel(LOGGER.getLevel());
        return level.ordinal() >= JulLevel.DEBUG.ordinal();
    }

    public static boolean isInfoEnabled() {
        JulLevel level = JulLevel.ofLevel(LOGGER.getLevel());
        return level.ordinal() >= JulLevel.INFO.ordinal();
    }

    public static boolean isWarnEnabled() {
        JulLevel level = JulLevel.ofLevel(LOGGER.getLevel());
        return level.ordinal() >= JulLevel.WARN.ordinal();
    }

    public static Logger getLogger() {
        return LOGGER;
    }
}
